/*
 *   Copyright 2012, Thomas Kerber
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
package milk.skimmed;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.regex.Pattern;

import milk.jpatch.JPatch;
import milk.skimmed.Jarp.Req;

/**
 * Contains information for generating jarps on-the-fly.
 * @author Thomas Kerber
 * @version 1.0.0
 */
public class JarpCreationInfo{
    
    /**
     * The class root to generate from.
     */
    private final File classRoot;
    /**
     * The jarps to require.
     */
    private final Jarp[] reqs;
    /**
     * The name of the jarp. (Without .jarp extension)
     */
    private final String name;
    
    /**
     * 
     * @param classRoot The class root to use.
     * @param reqs The jarps to require.
     * @param name The jarps name.
     */
    public JarpCreationInfo(File classRoot, Jarp[] reqs, String name){
        this.classRoot = classRoot;
        this.reqs = reqs;
        this.name = name;
    }
    
    /**
     * Creates the jarp.
     * @return The finalized jarp object.
     * @throws IOException
     * @throws MissingReqsException
     */
    public Jarp createJarp() throws IOException, MissingReqsException{
        File orig = Skimmed.genSelection(forceLoadReqs(reqs));
        File zip = File.createTempFile("milk-", ".zip");
        milk.jpatch.Util.packZip(zip, classRoot);
        File jarpF = new File(Skimmed.OPT_ROOT, name + ".jarp");
        File tmpExtracted = milk.jpatch.Util.getTempDir();
        try{
            JPatch.create(
                    orig.getAbsolutePath(),
                    zip.getAbsolutePath(),
                    tmpExtracted.getAbsolutePath());
        }
        catch(Exception e){
            Util.logger.log(Level.SEVERE, "JPatch create failed.", e);
            throw new IOException(e);
        }
        zip.delete();
        orig.delete();
        File props = new File(tmpExtracted, "milk.properties");
        StringBuilder reqsStr = new StringBuilder();
        boolean first = true;
        for(Jarp j : reqs){
            if(first)
                first = false;
            else
                reqsStr.append(", ");
            reqsStr.append(Pattern.quote(j.getName()).
                    replaceAll("[:=, ]", "\\\\$0"));
        }
        Writer out = new OutputStreamWriter(new FileOutputStream(props));
        out.write("# These Jarp properties are auto-generated. " +
                "They may be flawed or incomplete.\n\n");
        out.write("reqs = ");
        out.write(reqsStr.toString());
        out.close();
        milk.jpatch.Util.packZip(jarpF, tmpExtracted);
        milk.jpatch.Util.remDir(tmpExtracted);
        return new Jarp(jarpF);
    }
    
    /**
     * Resolved any requirements of required jarps.
     * @param jarps The required jarps.
     * @return The extended requirements list.
     * @throws MissingReqsException
     */
    private Jarp[] forceLoadReqs(Jarp[] jarps) throws MissingReqsException{
        List<Jarp> load = new ArrayList<Jarp>(Arrays.asList(jarps));
        load = forceLoadReqs(load);
        return load.toArray(new Jarp[load.size()]);
    }
    
    /**
     * Resolved any requirements of required jarps.
     * @param jarps The required jarps.
     * @return The extended requirements list.
     * @throws MissingReqsException
     */
    private List<Jarp> forceLoadReqs(List<Jarp> jarps)
            throws MissingReqsException{
        List<Req> missingReqs = new ArrayList<Req>();
        boolean reqsMissing = false;
        boolean changed = false;
        for(int i = 0; i < jarps.size(); i++){
            Req[] reqs = jarps.get(i).getReqs();
            for(int f = 0; f < reqs.length; f++){
                if(reqs[f].req == null){
                    missingReqs.add(reqs[f]);
                    reqsMissing = true;
                }
                else if(!reqsMissing && !jarps.contains(reqs[f].req)){
                    // FIXME: what happens if a req is already in the list but
                    // too late to work?
                    changed = true;
                    jarps.add(i++, reqs[f].req);
                }
            }
        }
        if(reqsMissing)
            throw new MissingReqsException(missingReqs);
        if(changed)
            jarps = forceLoadReqs(jarps);
        return jarps;
    }
    
}
